Next | Prev | Up | Top | Contents | Index

The Texture Extension Proxy Mechanism

In OpenGL 1.0, it's difficult to find out whether a texture fits into texture memory on a certain system. When you call glGetIntegerv() with the parameter GL_MAX_TEXTURE_SIZE, you can't be sure of an accurate result: Texel format, component resolution, and the shape of a texture determine whether the texture fits. To ensure that a texture of any format and resolution fits, the function returns a result based on the worst-case scenario.

A solution to this problem is the proxy mechanism offered by the texture extension. To test whether a certain texture fits, follow these steps:

  1. Call glTexImage2D() or glTexImage1D() with target set to GL_PROXY_TEXTURE_2D_EXT or GL_PROXY_TEXTURE_1D_EXT (see Example 6-1).

  2. Test the proxy texture state values to see if the texture would fit and how it would be stored in texture memory by calling glGetTexLevelParameteriv() or glGetTexLevelParameterfv(). Set target to one of the proxy textures: GL_PROXY_TEXTURE_2D_EXT or GL_PROXY_TEXTURE_1D_EXT. Set pname to the parameter you are interested in, for example, GL_TEXTURE_WIDTH. If the call returns non-zero, the texture will fit.

    If the texture is too large, all of the proxy state variables are set to zero. If the texture can be accommodated, these values are set to the requested parameters. The proxy 1-D texture behaves like the proxy 2-D texture; however, its state does not include GL_TEXTURE_HEIGHT.

    You still need to call glTexImage2D() with target GL_TEXTURE_2D to define the actual texture.

  3. To determine the maximum array size for a mipmap texture, specify and query the proxy texture at the highest level that accurately reflects the aspect ratio of the desired level zero array.
Example 6-1 provides a code fragment that determines the largest texture that can be allocated for a given internal image format and aspect ratio. The program incrementally selects larger textures to find the maximum that will fit.

Example 6-1 : Using the Proxy Mechanism

/*
** Demonstrates use of the proxy texture target to probe texture space 
** to determine the largest texture which can be allocated for a given 
** internal image format and aspect ratio. 
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <GL/gl.h>
#include <GL/glu.h>

/* (int)floor(log2(x)) */
static int
intFloorLog2(unsigned int x)
{
    int a = 0;
    while (x >>= 1) ++a;
    return a;
}

/* true if x is a power of two */
static GLboolean
isPow2(unsigned int x)
{
    return ((x > 0) && (x & (x - 1) == 0));
}

/* find largest texture with specified internal format and aspect */
static void
findMaxTexture(GLenum internalFormat, int dim,
    int xAspect, int yAspect, int border, int maxMipmapLevel,
    int *widthOut, int *heightOut)
{
    int level = 0, levelOffset = 0;
    int width = 1, height = 1;
    int maxLevel = 0, maxWidth = 0, maxHeight = 0;

    if (xAspect > yAspect) {
        width = xAspect / yAspect;
        levelOffset = intFloorLog2(width);
    } else {
        height = yAspect / xAspect;
        levelOffset = intFloorLog2(height);
    }

    while (1) {
        GLint proxyComponents;

        switch (dim) {
          case 1:
            glTexImage1D(GL_PROXY_TEXTURE_1D_EXT,
                         level, internalFormat,
                         width+2*border, border,
                         GL_RGBA, GL_UNSIGNED_BYTE, NULL);
            
            glGetTexLevelParameteriv(GL_PROXY_TEXTURE_1D_EXT, level,
                    GL_TEXTURE_COMPONENTS, &proxyComponents);
            break;
          case 2:
            glTexImage2D(GL_PROXY_TEXTURE_2D_EXT,
                     level, internalFormat,
                     width+2*border, height+2*border, border,
                     GL_RGBA, GL_UNSIGNED_BYTE, NULL);
               
            glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D_EXT,level
                     GL_TEXTURE_COMPONENTS,&proxyComponents);
            break;
          default:
            *widthout = 0; 
            *heightout = 0;
            return;
        }
        
        if (proxyComponents != internalFormat) {
           /* proxy allocation failed -- we're done */
            break;
        } else {
           /* proxy allocation succeeded -- see how we did */
               if (level>maxLevel || width>maxWidth || 
                                                    height>maxHeight)
            {
                maxLevel = level;
                maxWidth = width << level;
                maxHeight = height << level;
            }
        }

        if (maxMipmapLevel == 0) {
       /* try the next larger image size at level zero */
            width <<= 1;
            height <<= 1;
        } else {
       /* try same image size at next higher mipmap level */
            ++level;
            if (level+levelOffset > maxMipmapLevel) {
       /* can't query levels which don't exist--we're done */
                break;
            }
        }
    }

    if (maxWidth>0 && maxHeight>0) {
        maxWidth += 2*border;
        maxHeight += 2*border;
    }
    *widthOut = maxWidth;
    *heightOut = maxHeight;
}
static void
displayTextureSizeInfo(void)
{
    GLint maxTextureSize, maxTextureLevel;
    int maxWidth, maxHeight;

    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
    printf("GL_MAX_TEXTURE_SIZE: %d\n", maxTextureSize);

    maxTextureLevel = intFloorLog2(maxTextureSize);

    findMaxTexture(GL_RGB, 2, 1, 1, 0, 0, &maxWidth, &maxHeight);
    printf("RGB 1:1 (%d x %d)\n", maxWidth, maxHeight);

    findMaxTexture(GL_RGBA, 2, 2, 1, 0, 0, &maxWidth, &maxHeight);
    printf("RGBA 2:1 (%d x %d)\n", maxWidth, maxHeight);

    findMaxTexture(GL_RGB, 2, 1, 1, 0, maxTextureLevel, &maxWidth, 
                                                        &maxHeight);
    printf("RGB 1:1 (%d x %d) mipmap\n", maxWidth, maxHeight);

    findMaxTexture(GL_LUMINANCE_ALPHA, 2, 1, 1, 1, 0, &maxWidth, 
                                                      &maxHeight);
    printf("LUMINANCE_ALPHA 1:1 (%d x %d) w/border\n", maxWidth,
                                                       maxHeight);
}

Next | Prev | Up | Top | Contents | Index